// Copyright (C) 2019-2021
// 511972386@qq.com

#include "../include/someip_service.hpp"


namespace someip_app {

static vsomeip::service_t service_id = 0x1111;
static vsomeip::instance_t service_instance_id = 0x2222;
static vsomeip::method_t service_method_id = 0x3333;

// Get the vSomeIP runtime and
    // create a application via the runtime, we could pass the application name
    // here otherwise the name supplied via the someip_service LICATION_NAME
    // environment variable is used
someip_service::someip_service():
                rtm_(vsomeip::runtime::get()),
                app_(rtm_->create_application()),
                stop_(false),
                stop_thread_(std::bind(&someip_service::stop, this))
{
}

someip_service::~someip_service()
{
    terminate();
    stop_thread_.join();
}

bool someip_service::init()
{
    // init the application
    if (!app_->init()) {
        std::cerr << "Couldn't initialize application" << std::endl;
        return false;
    }

    // register a message handler callback for messages sent to our service
    app_->register_message_handler(service_id, service_instance_id,
            service_method_id,
            std::bind(&someip_service::on_message_cbk, this,
                    std::placeholders::_1));

    // register a state handler to get called back after registration at the
    // runtime was successful
    app_->register_state_handler(
            std::bind(&someip_service::on_state_cbk, this,
                    std::placeholders::_1));
    return true;
}

void someip_service::start()
{
    // start the application and wait for the on_event callback to be called
    // this method only returns when app_->stop() is called
    app_->start();
}

void someip_service::stop()
{
    std::unique_lock<std::mutex> its_lock(mutex_);
    while(!stop_) {
        condition_.wait(its_lock);
    }

    std::this_thread::sleep_for(std::chrono::seconds(5));
    // Stop offering the service
    app_->stop_offer_service(service_id, service_instance_id);
    // unregister the state handler
    app_->unregister_state_handler();
    // unregister the message handler
    app_->unregister_message_handler(service_id, service_instance_id,
            service_method_id);
    // shutdown the application
    app_->stop();
}

void someip_service::terminate() {
    std::lock_guard<std::mutex> its_lock(mutex_);
    stop_ = true;
    condition_.notify_one();
}

void someip_service::on_state_cbk(vsomeip::state_type_e _state)
{
    if(_state == vsomeip::state_type_e::ST_REGISTERED)
    {
        // we are registered at the runtime and can offer our service
        app_->offer_service(service_id, service_instance_id);
    }
}

void someip_service::on_message_cbk(const std::shared_ptr<vsomeip::message> &_request)
{
    // Create a response based upon the request
    std::shared_ptr<vsomeip::message> resp = rtm_->create_response(_request);

    // Construct string to send back
    std::string str("Hello ");
    str.append(
            reinterpret_cast<const char*>(_request->get_payload()->get_data()),
            0, _request->get_payload()->get_length());

    // Create a payload which will be sent back to the client
    std::shared_ptr<vsomeip::payload> resp_pl = rtm_->create_payload();
    std::vector<vsomeip::byte_t> pl_data(str.begin(), str.end());
    resp_pl->set_data(pl_data);
    resp->set_payload(resp_pl);

    // Send the response back
    app_->send(resp, true);
    // we have finished
    terminate();
}


} // namespace someip_app
